package com.onpositive.data.serializer.readers;

import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.BitSet;
import java.util.Date;
import java.util.LinkedHashSet;

import com.onpositive.data.FilterTester;
import com.onpositive.data.IWritable;
import com.onpositive.data.serializer.writers.AbstractWriter;
import com.onpositive.data.serializer.writers.DateWithAccuracyWriter;
import com.onpositive.data.units.DateWithAccuracy;

public class DateWithAccuracyReader extends CollectionReader<DateWithAccuracy> implements IWritable{

	// private static final int INT_SIZE = 4 ;
	private final static DateWithAccuracy defaultDate = new DateWithAccuracy(0);
	private static final int defaultIntValue = Integer.MIN_VALUE;
	private DateWithAccuracy[] dateWithAccuracyArrays;

	public DateWithAccuracyReader() {
		super(DateWithAccuracy.class);
	}

	@Override
	protected void initValuesAray(byte[] byteData) {

		int[] primitiveValuesArray = new int[size];

		ByteBuffer bBuf = ByteBuffer.wrap(byteData);

		boolean continueIteration = true;
		int start = 0;
		int end = emptyCells.nextSetBit(0);
		for (; continueIteration;) {
			for (int i = start; i < end; i++)
				primitiveValuesArray[i] = bBuf.getInt();

			if (end < size)
				primitiveValuesArray[end] = defaultIntValue;

			start = end + 1;
			end = emptyCells.nextSetBit(start);
			end = end >= 0 ? end : size;
			continueIteration = start <= size;
		}
		dateWithAccuracyArrays = new DateWithAccuracy[size];
		for (int i = 0; i < size; i++)
			dateWithAccuracyArrays[i] = new DateWithAccuracy(
					primitiveValuesArray[i]);

		
	}

	@Override
	protected DateWithAccuracy doGet(int i) {
		return dateWithAccuracyArrays[i];
	}

	@Override
	protected DateWithAccuracy defaultObject() {
		return defaultDate;
	}

	@Override
	protected DateWithAccuracy readObject(ByteBuffer bBuf) {

		return new DateWithAccuracy(bBuf.getInt());
	}

	@Override
	public void filterOut(LinkedHashSet<Object> obj, String text) {

	}

	public boolean hasValue(int po) {
		if (!isInitialized()) {
			init();
		}
		return !emptyCells.get(po);
	}

	@Override
	public boolean accept(int op, int a, Object constraint) {
		if (!isInitialized())
			init();
		boolean b = emptyCells.get(a);
		if (constraint == null) {
			switch (op) {
			case FilterTester.LE:
			case FilterTester.GE:
			case FilterTester.EQ:
				return b;

			case FilterTester.LT:
			case FilterTester.GT:
			case FilterTester.NEQ:
				return !b;

			default:
				break;
			}
			return false;
		}
		if (b) {
			switch (op) {
			case FilterTester.LE:
			case FilterTester.NEQ:
			case FilterTester.LT:
				return true;

			default:
				break;
			}
			return false;
		}
		if (constraint instanceof DateWithAccuracy) {
			DateWithAccuracy m = (DateWithAccuracy) constraint;
			constraint = m.getDate();
		}
		DateWithAccuracy[] dateWithAccuracies = (DateWithAccuracy[]) dateWithAccuracyArrays;
		if (dateWithAccuracies == null) {
			setUninitialized();
			init();
		}
		long i = (dateWithAccuracies[a]).getDate().getTime();
		// FIXME
		Date m = (Date) constraint;

		long ww = m.getTime();
		switch (op) {
		case FilterTester.EQ:
			return ww == i;
		case FilterTester.NEQ:
			return ww != i;
		case FilterTester.LE:
			return ww >= i;
		case FilterTester.LT:
			return ww > i;
		case FilterTester.GT:
			return ww < i;
		case FilterTester.GE:
			return ww <= i;
		case FilterTester.CONTAINS:
			return ww == i;
		default:
			throw new UnsupportedOperationException();
		}
	}

	@Override
	public void setValue(int index, Object value) {
		if (!isInitialized()){
			init();
		}
		if (value==null){
			emptyCells.set(index);
			return;
		}
		else{
			emptyCells.clear(index);
			if (value instanceof Date){
				value=new DateWithAccuracy((Date) value, DateWithAccuracy.ACCURACY_DAY);
			}
			dateWithAccuracyArrays[index]=((DateWithAccuracy) value);
		}		
		
	}

	@Override
	public void serialize(DataOutputStream ds) throws IOException {
		if (!isInitialized()) {
			init();
		}
		DateWithAccuracyWriter we = new DateWithAccuracyWriter();
		for (int a = 0; a < dateWithAccuracyArrays.length; a++) {
			if(hasValue(a)){
				we.append(dateWithAccuracyArrays[a]);
			}
			else{
				we.append(null);
			}
		}
		we.serialize(ds);
	}

	@Override
	public Object aggregate(int op, BitSet ss) {
		if (!isInitialized()) {
			init();
		}
		ComparingAggregator comparingAggregator = new ComparingAggregator();
		comparingAggregator.mode=(op==AGR_MIN)?ComparingAggregator.MIN_MODE:ComparingAggregator.MAX_MODE;
		return comparingAggregator.getAggregatedValue(dateWithAccuracyArrays,ss);
	}

	@Override
	public AbstractWriter<DateWithAccuracy> getWriter() {
		return new DateWithAccuracyWriter();
	}

	@Override
	public void initEmpty(int dataSize) {
		emptyCells=new BitSet(dataSize);
		dateWithAccuracyArrays=new DateWithAccuracy[dataSize];
		setInitialized();
	}

	@Override
	public void expand(int newSize) {
		if (!isInitialized()){
			init();
		}
		DateWithAccuracy[] m=new DateWithAccuracy[newSize];
		System.arraycopy(dateWithAccuracyArrays, 0, m, 0, dateWithAccuracyArrays.length);
		dateWithAccuracyArrays=m;
	}

}
